package com.engine4cloud.tdf.education.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.engine4cloud.tdf.common.core.exception.ValidateCodeException;
import com.engine4cloud.tdf.common.data.web.query.Pages;
import com.engine4cloud.tdf.common.data.web.query.Queries;
import com.engine4cloud.tdf.common.data.web.response.PageInfo;
import com.engine4cloud.tdf.common.security.service.TdfUser;
import com.engine4cloud.tdf.common.security.util.SecurityUtils;
import com.engine4cloud.tdf.education.convert.EduStudyTaskConvert;
import com.engine4cloud.tdf.education.dto.EduCourseResourcePushDTO;
import com.engine4cloud.tdf.education.dto.query.EduStudentTaskAppQueryDTO;
import com.engine4cloud.tdf.education.dto.query.EduStudentTaskQueryDTO;
import com.engine4cloud.tdf.education.dto.result.EduStudyTaskResultDTO;
import com.engine4cloud.tdf.education.dto.result.EduStudentResultDTO;
import com.engine4cloud.tdf.education.entity.EduStudyTaskEntity;
import com.engine4cloud.tdf.education.mapper.EduStudyTaskMapper;
import com.engine4cloud.tdf.education.service.EduStudyTaskService;
import com.engine4cloud.tdf.education.service.EduStudentService;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 学生课程关系
 *
 * @author wenjie
 * @date 2024-07-30 14:58:44
 */
@Service
public class EduStudyTaskServiceImpl extends ServiceImpl<EduStudyTaskMapper, EduStudyTaskEntity> implements EduStudyTaskService {

    @Lazy
    @Resource
    private EduStudentService studentService;

    @Override
    public PageInfo<EduStudyTaskResultDTO> pageList(EduStudentTaskAppQueryDTO dto) {
        return Pages.convert(this.baseMapper.pageList(Pages.page(dto), dto));
    }

    @Override
    public EduStudyTaskResultDTO getById(Long id) {
        return this.baseMapper.getDetailById(id);
    }

    @Override
    public List<EduStudyTaskResultDTO> findList(String courseCode, List<String> groupCodeList, List<String> resourceCodeList) {
        return this.list(wrapperList(courseCode, groupCodeList, resourceCodeList)).stream().map(EduStudyTaskConvert.INSTANCE::convert).toList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean createBatch(String courseCode, List<String> groupList, List<String> resourceList) {
        List<EduStudentResultDTO> studentList = studentService.findMutList(groupList);
        if (CollectionUtils.isEmpty(studentList)) {
            throw new ValidateCodeException("请为学组设置学生");
        }

        List<EduStudyTaskResultDTO> existList = this.findList(courseCode, groupList, resourceList);
        //构建学生资源列表
        List<EduStudyTaskEntity> preliminaryList = this.preliminaryList(courseCode, resourceList, studentList);
        //去除已经有课程资源的学生(分开写是为了将多层循环拆分成2个)
        List<EduStudyTaskEntity> ultimateList = this.ultimateList(existList, preliminaryList);

        if (CollectionUtils.isNotEmpty(ultimateList)) {
            super.saveBatch(ultimateList);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean createBatch(EduCourseResourcePushDTO dto, List<String> resourceList) {
        List<EduStudyTaskResultDTO> existList = this.findList(dto.getCourseCode(), new ArrayList<>(Collections.singletonList(dto.getGroupCode())), resourceList);
        //构建学生资源列表

        List<EduStudyTaskEntity> preliminaryList = this.preliminaryList(dto.getCourseCode(), dto.getGroupCode(), resourceList, dto.getStudentCodeList());
        //去除已经有课程资源的学生(分开写是为了将多层循环拆分成2个)
        List<EduStudyTaskEntity> ultimateList = this.ultimateList(existList, preliminaryList);

        if (CollectionUtils.isNotEmpty(ultimateList)) {
            super.saveBatch(ultimateList);
        }

        return true;
    }

    @Override
    public EduStudyTaskResultDTO findByCode(String code) {
        return EduStudyTaskConvert.INSTANCE.convert(super.getOne(wrapper(new EduStudentTaskQueryDTO(code))));
    }

    private List<EduStudyTaskEntity> preliminaryList(String courseCode, List<String> resourceList, List<EduStudentResultDTO> studentList) {
        List<EduStudyTaskEntity> preliminaryList = new ArrayList<>();
        TdfUser user = SecurityUtils.getUser();
        for (EduStudentResultDTO s : studentList) {
            resourceList.forEach(resourceCode -> {
                EduStudyTaskEntity entity = EduStudyTaskConvert.INSTANCE.create(courseCode, s.getGroupCode(), resourceCode, s.getCode(), user.getTenantId());
                preliminaryList.add(entity);
            });
        }
        return preliminaryList;
    }

    private List<EduStudyTaskEntity> preliminaryList(String courseCode, String groupCode, List<String> resourceList, List<String> studentCodeList) {
        List<EduStudyTaskEntity> preliminaryList = new ArrayList<>();
        TdfUser user = SecurityUtils.getUser();
        for (String studentCode : studentCodeList) {
            resourceList.forEach(resourceCode -> {
                EduStudyTaskEntity entity = EduStudyTaskConvert.INSTANCE.create(courseCode, groupCode, resourceCode, studentCode, user.getTenantId());
                preliminaryList.add(entity);
            });
        }
        return preliminaryList;
    }

    private List<EduStudyTaskEntity> ultimateList(List<EduStudyTaskResultDTO> existList, List<EduStudyTaskEntity> preliminaryList) {
        List<EduStudyTaskEntity> ultimateList = new ArrayList<>();
        TdfUser user = SecurityUtils.getUser();

        if (CollectionUtils.isNotEmpty(existList)) {

            Map<String, EduStudyTaskEntity> preliminaryMap = preliminaryList.stream().collect(Collectors.toMap(EduStudyTaskEntity::getStudentCode, Function.identity(), (v1, v2) -> v1));

            List<EduStudyTaskEntity> duplicatedList = new ArrayList<>();
            //去除已经存在的
            for (EduStudyTaskEntity entity : preliminaryList) {
                existList.forEach(exist -> {
                    if (Objects.equals(entity.getGroupCode(), exist.getGroupCode()) &&
                            Objects.equals(entity.getResourceCode(), exist.getResourceCode()) && Objects.equals(entity.getStudentCode(), exist.getStudentCode())) {
                        duplicatedList.add(entity);
                    }
                });
            }

            if (CollectionUtils.isNotEmpty(duplicatedList)) {
                duplicatedList.forEach(dup -> {
                    if (preliminaryMap.containsKey(dup.getStudentCode())) {
                        EduStudyTaskEntity exit = preliminaryMap.get(dup.getStudentCode());
                        if (Objects.equals(exit.getGroupCode(), dup.getGroupCode()) && Objects.equals(exit.getResourceCode(), dup.getResourceCode())) {
                            preliminaryMap.remove(dup.getStudentCode());
                        }
                    }
                });
            }

            if (MapUtils.isNotEmpty(preliminaryMap)) {
                ultimateList.addAll(preliminaryMap.values().stream().map(
                        eduStudentResourceEntity -> EduStudyTaskConvert.INSTANCE.create(
                                eduStudentResourceEntity.getCourseCode(),
                                eduStudentResourceEntity.getGroupCode(),
                                eduStudentResourceEntity.getResourceCode(),
                                eduStudentResourceEntity.getStudentCode(),
                                user.getTenantId())).toList());
            }
        } else {
            ultimateList.addAll(preliminaryList);
        }


        return ultimateList;
    }

    private LambdaQueryWrapper<EduStudyTaskEntity> wrapperList(String courseCode, List<String> groupCodeList, List<String> resourceCodeList) {
        LambdaQueryWrapper<EduStudyTaskEntity> wrapper = Queries.lambda();
        Queries.accept(courseCode, v -> wrapper.eq(EduStudyTaskEntity::getCourseCode, v));
        Queries.accept(groupCodeList, v -> wrapper.in(EduStudyTaskEntity::getGroupCode, v));
        Queries.accept(resourceCodeList, v -> wrapper.in(EduStudyTaskEntity::getResourceCode, v));
        return wrapper;
    }

    private LambdaQueryWrapper<EduStudyTaskEntity> wrapper(EduStudentTaskQueryDTO query) {
        LambdaQueryWrapper<EduStudyTaskEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(EduStudyTaskEntity::getId, v));
        Queries.accept(query.getCode(), v -> wrapper.in(EduStudyTaskEntity::getCode, v));
        Queries.accept(query.getCourseCode(), v -> wrapper.in(EduStudyTaskEntity::getCourseCode, v));
        Queries.accept(query.getGroupCode(), v -> wrapper.in(EduStudyTaskEntity::getGroupCode, v));
        Queries.accept(query.getStudentCode(), v -> wrapper.in(EduStudyTaskEntity::getStudentCode, v));
        return wrapper;
    }
}